from django.shortcuts import render

# Create your views here.
from django_redis import get_redis_connection
from rest_framework.response import Response

from goods.models import SKU

"""
1.未登录用户的购物车数据保存在cookie中
2.登录用户的购物车数据保存在库中 ，mysql也可以，Redis也可以， 把数据保存在redis中

3.点击加入购物车 需要将 商品id，商品购买数据，是否选中保存起来

4. 设计 如何把数据保存在Redis中

   保存： sku_id,count,selected

   类型： string,hash,list,set,zset

   原则：  Redis的数据是保存在 内存中。 占用越少越好
          满足我们的代码需要

    Hash:
    h_key: {
        key1:value,
        key2:value,
    }

    1: {

        1:5,
    }


    # 单独定义一个 选中的集合
    #需要用程序区判断一下，如果 id，在列表中，表示选中，没有则表示 没有选中
    [1]



    cookie的数据在 浏览器端，怎么保存都可以
    {
        sku_id: {
            count:4,
            selected:True
        }
    }


5.  pickle
    base64

1G = 1024M
1M = 1024Kb
1K = 1024B
1B = 8bit

11000011   10000101    11110000   24bit
    a           b          c


110000          111000      010111          110000
  z                 y           x               l


    base64:



"""

from rest_framework.views import APIView
from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer
import pickle
import base64
from rest_framework import status

class CartView(APIView):

    """
    # 1.获取user
    # 2.判断是否登录
    # 3.登录用户保存在redis中
    # 4.未登录用户保存在cookie中
    # 5.返回响应

    POST        carts/       增加购物车功能
    """

    # 在运行post之前 系统对token进行了验证
    # 我们先不让系统验证，等我们使用的时候，再验证
    def perform_authentication(self, request):
        pass


    def post(self,request):

        # 0.获取用户提交的数据(sku_id,count,selected)，并对数据进行校验
        data = request.data
        serializer = CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)

        #获取验证之后的数据，以便 保存到redis或者cookie中
        sku_id = serializer.data.get('sku_id')
        count = serializer.data.get('count')
        selected = serializer.validated_data.get('selected')


        # 1.获取user
        try:
            user = request.user
        except Exception as e:
            user = None
        # 需要使用user的时候 user可能会存在异常，异常我们就认为 user=None

        # 2.判断是否登录

        # request.user.is_authenticated
        # is_authenticated 是否是认证登录用户

        if user is not None and user.is_authenticated:
            #    3.登录用户保存在redis中

            #3.1连接redis
            redis_conn = get_redis_connection('cart')
            #3.2 保存数据

            # hash: hash_key: {sku_id:count}
            # redis_conn.hset('cart_%s'%user.id,sku_id,count)
            # 可以用累加的方式

            # 创建管道
            pl = redis_conn.pipeline()

            pl.hincrby('cart_%s'%user.id,sku_id,count)


            # set: set_key: [selected_id]
            pl.sadd('cart_selected_%s'%user.id,sku_id)

            #让管道去执行
            pl.execute()

            # 3.2 返回响应
            return Response(serializer.data)



        else:
            # 4.未登录用户保存在cookie中
            # 可能之前存在cookie数据
            # 可能之前不存在cookie数据

            # 4.1  先读取之前可能存在的cookie
            cookie_str = request.COOKIES.get('cart')
            # 4.2 判断
            if cookie_str is not None:
                #有值
                decode = base64.b64decode(cookie_str)

                cart = pickle.loads(decode)
                # {1:{count:5,selected:True}}
            else:
                #没有值
                cart = {}

            #4.3  判断商品id是否在cookie中存在
            if sku_id in cart:
                ## {1:{count:5,selected:True}}
                #存在就进行累加
                orginal_count = cart[sku_id]['count']

                count += orginal_count

                # cart[sku_id]['count'] = count


            # 4.4 更新数据
            cart[sku_id] = {
                'count':count,
                'selected':selected
            }




            # 4.5.设置cookie，返回响应
            response = Response(serializer.data)

            # 将字典转换为二进制
            dumps = pickle.dumps(cart)
            #将二进制进行base64编码
            encode = base64.b64encode(dumps)

            cookie_cart = encode.decode()

            response.set_cookie('cart',cookie_cart)

            return response



    def get(self,request):
        """
        # 1.获取user
        # 2.判断是否登录
        # 3.登录用户保存在redis中
            #连接redis
            #hash {sku_id:count}
            #set [sku_id]
            #最终要获取所有的id 【1,2,3,4,】


        # 4.未登录用户保存在cookie中
            获取cookie数据，进行判断
            如果存在，则获取id   【1,2,3,4】

            【1,2,3,4】
        # 5.根据id获取商品信息     【SKU,SKU,SKU】
        # 6.创建序列化器将对象列表转换为JOSN

        """
        # 1.获取user
        try:
            user = request.user
        except Exception as e:
            user = None
        # 2.判断是否登录
        if user is not None and user.is_authenticated:

            # 3.登录用户保存在redis中
            # 连接redis
            redis_conn = get_redis_connection('cart')
            # hash {sku_id:count}
            sku_count_ids = redis_conn.hgetall('cart_%s'%user.id)
            # set [sku_id]
            sku_selected_ids = redis_conn.smembers('cart_selected_%s'%user.id)



            #将redis数据结构转换为 cookie结果
            #{1:{count:xx,select:xxx}}

            cart = {}
            for sku_id,count in sku_count_ids.items():

                cart[int(sku_id)] = {
                    'count':int(count),
                    'selected':sku_id in sku_selected_ids
                }



        else:

            # 4.未登录用户保存在cookie中
            # 获取cookie数据，进行判断
            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                decode = base64.b64decode(cookie_str)
                cart = pickle.loads(decode)
                # {1:{count:xx,select:xxx}}
            else:
                cart = {}


         # 获取id   【1, 2, 3, 4】
        ids = cart.keys()

        # 5.根据id获取商品信息     【SKU,SKU,SKU】
        skus = SKU.objects.filter(pk__in=ids)

        # 我们需要给SKU 传递 count和select数据
        for sku in skus:
            ## {1:{count:xx,select:xxx}}
            #动态的给属性添加值
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']

        # 6.创建序列化器将对象列表转换为JOSN

        serializer = CartSKUSerializer(skus,many=True)

        return Response(serializer.data)


    def put(self,request):
        """
        修改购物车的数据 ： sku_id,count,selected
                        幂等  最终的个数返回给我们，更新之后，我们需要将 个数返回

        #1.获取前端提交的数据
        #2.校验数据
        #3.获取数据
        #4 .获取user
        # 5.判断是否登录
        #6 .登录用户保存在redis中
            #6.1 连接redis
            #6.2 修改数据
            #   hash
            #   set
            # 6.3返回响应
        # 7.未登录用户保存在cookie中
            #7.1 获取cookie数据进行判断
            #7.2 修改数据
            #7.3 设置cookie返回响应

        """
        # 1.获取前端提交的数据
        data = request.data
        # 2.校验数据
        serializer = CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 3.获取数据
        sku_id = serializer.data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')
        # 4 .获取user
        try:
            user = request.user
        except Exception as e:
            user = None
        # 5.判断是否登录
        if user is not None and user.is_authenticated:

            # 6 .登录用户保存在redis中
            # 6.1 连接redis
            redis_conn = get_redis_connection('cart')
            # 6.2 修改数据
            #   hash
            #因为我们是采用的幂等（将最终结果返回） 1:120
            # 1:10
            redis_conn.hset('cart_%s'%user.id,sku_id,count)

            #   set  [1]
            if selected:
                #选中
                redis_conn.sadd('cart_selected_%s'%user.id,sku_id)
            else:
                #未选中
                redis_conn.srem('cart_selected_%s'%user.id,sku_id)


            # 6.3返回响应
            #把最终的结果返回回去
            return Response(serializer.data)

        else:
            # 7.未登录用户保存在cookie中
            # 7.1 获取cookie数据进行判断
            cookie_str = request.COOKIES.get('cart')

            if cookie_str is not None:
                #有
                cart = pickle.loads(base64.b64decode(cookie_str))
            else:
                #没有
                cart = {}


            # 7.2 修改数据
            # {1：{count:xxx,selected:xxx}}
            if sku_id in cart:
                #修改
                cart[sku_id] = {
                    'count':count,
                    'selected':selected
                }


            # 7.3 设置cookie返回响应
            response = Response(serializer.data)

            cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()

            response.set_cookie('cart',cookie_cart)

            return response

    def delete(self,request):

        """
        # 1.接受参数
        #2.校验参数
        #3.获取参数
        # 4.获取user
        # 5.判断是否登录
        # 6.登录用户保存在redis中
            # 连接redis
            # 删除数据
            # hash
            # set
            #返回响应
        # 7.未登录用户保存在cookie中
            # 获取cookie数据进判断
            # 删除数据
            # 设置cookie返回响应



        """
        # 1.接受参数
        data = request.data
        # 2.校验参数
        serializer = CartDeleteSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 3.获取参数
        sku_id = serializer.data.get('sku_id')
        # 4.获取user
        try:
            user = request.user
        except Exception as e:
            user = None
        # 5.判断是否登录
        if user is not None and user.is_authenticated:

            # 6.登录用户保存在redis中
            # 连接redis
            redis_conn = get_redis_connection('cart')
            # 删除数据
            # hash
            redis_conn.hdel('cart_%s'%user.id,sku_id)
            # set
            redis_conn.srem('cart_selected_%s'%user.id,sku_id)
            # 返回响应

            return Response(status=status.HTTP_204_NO_CONTENT)

        else:
            # 7.未登录用户保存在cookie中
            # 获取cookie数据进判断
            cookie_str = request.COOKIES.get('cart')

            if cookie_str is not None:
                #有
                cart = pickle.loads(base64.b64decode(cookie_str))
            else:
                cart = {}
            # 删除数据
            if sku_id in cart:
                del cart[sku_id]

            # 设置cookie返回响应
            response = Response(status=status.HTTP_204_NO_CONTENT)

            cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()

            response.set_cookie('cart',cookie_cart)

            return response




"""
登录的时候 将 cookie数据合并到 redis中


#已知cookie数据   --》 Redis

cookie:
    {
        sku_id： {count:5,select:True}
    }

Redis
    Hash        {sku_id:count}
    Set            [sku_id]

###################################################################

把抽象的事情 具体化

#合并：
# cookie --> redis

# 考虑id:         如果cookie中有的id，redis中 没有 ，则添加到redis中
# 考虑id:         如果cookie中没有id，redis中也有 ，则 redis不变

# 考虑id:         如果cookie中有的id，redis中也有 ，则

# count          cookie也有，redis也有：
        有三种情况： 以Redis为准，以Cookie为准，以累加为准
        怎么选都可以。 我们选择以 COOKIE为准

#1.获取cookie数据
cookie:  {1:{count:5,selected:True},3:{count:10:selected:False}}


#2. 获取redis数据
redis:
        hash:       {2:100,3:50}
        set         [2,3]

#3. 合并
# 最终的结果
# hash: {1:5,2:100,3:10}
# set   [1,2,3]


#4.把最终的结果 添加到redis中

#5.合并成功之后，删除cookie数据











"""